from django.db import transaction
from django.utils import translation
from ability.enums import ErrorCode
from rest_framework import mixins, viewsets
from ability.serializer.course import ChapterCreateSerializer, CourseStudentsSerializer
import traceback
from django.db.models.query_utils import Q
from ability.format import CustomResponse, GetPostParaOrNone
from ability.models import Chapter, Course, Exam, ExamQuestion, Paper, Question, Knowledge, Student
from ability.serializer.serializers import ChapterSerializer, ExamCreateSerializer, ExamSerializer, PaperListSerializer
from rest_framework.generics import ListAPIView
from rest_framework.response import Response
from rest_framework.serializers import Serializer
from rest_framework.views import APIView
from ability.excepts import LogicException
import ability.permissions as pm
from rest_framework import permissions
import random
import ability.timeutil as timeutil
from datetime import datetime

class ExamStatusAction(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ExamStatusAction, self).__init__(**kwargs)

    def post(self, request, *args, **kwargs):
        try:
            status = GetPostParaOrNone(request.data, 'status')
            if status not in ['N', 'S']:
                raise LogicException('参数不正确')
            model = Exam.get_by_pk_user(kwargs['exam_id'], self.request.user)
            if model is None:
                raise LogicException('数据不存在')
            model.status = status
            model.save()
            self.response_format['message'] = '操作成功'
            return Response(self.response_format)
        except LogicException as e: 
            self.response_format["message"] = str(e)
            self.response_format["error_code"] = -1 
            return Response(self.response_format)
        except Exception as e:
            traceback.print_exc()
            self.response_format["message"] = str(e)
            self.response_format["error_code"] = -1 
            return Response(self.response_format)

class ExamCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = ExamCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ExamCreateViewSet, self).__init__(**kwargs)

    def store_exam(self, request, serializer):
        knowledges = GetPostParaOrNone(self.request.data,"knowledges")
        exam= serializer.save()
        exam.question_total = int(self.request.data['MC']['total']) + int(self.request.data['MA']['total']) + int(self.request.data['TF']['total']) + int(self.request.data['BL']['total']) + int(self.request.data['SA']['total'])
        exam.mc_total = int(self.request.data['MC']['total'])
        exam.ma_total = int(self.request.data['MA']['total'])
        exam.tf_total = int(self.request.data['TF']['total'])
        exam.bl_total = int(self.request.data['BL']['total'])
        exam.sa_total = int(self.request.data['SA']['total'])
        exam.mc_score = int(self.request.data['MC']['score'])
        exam.ma_score = int(self.request.data['MA']['score'])
        exam.tf_score = int(self.request.data['TF']['score'])
        exam.bl_score = int(self.request.data['BL']['score'])
        exam.sa_score = int(self.request.data['SA']['score'])
        exam.owner = self.request.user
        exam.save()
        for k in knowledges:
            kmodel = Knowledge.objects.get(id=k)
            exam.knowledge.add(kmodel)
        return exam

    def perform_create(self, serializer):
        assert int(self.request.data['MC']['score']) + int(self.request.data['MA']['score']) + int(self.request.data['TF']['score']) + int(self.request.data['BL']['score']) + int(self.request.data['SA']['score']) == 100
        assert int(self.request.data['MC']['total']) + int(self.request.data['MA']['total']) + int(self.request.data['TF']['total']) + int(self.request.data['BL']['total']) + int(self.request.data['SA']['total']) > 0
        assert int(self.request.data['MC']['score']) % int(self.request.data['MC']['total']) == 0
        assert int(self.request.data['MA']['score']) % int(self.request.data['MA']['total']) == 0
        assert int(self.request.data['TF']['score']) % int(self.request.data['TF']['total']) == 0
        assert int(self.request.data['BL']['score']) % int(self.request.data['BL']['total']) == 0
        assert int(self.request.data['SA']['score']) % int(self.request.data['SA']['total']) == 0
        knowledges = GetPostParaOrNone(self.request.data,"knowledges")
        if len(knowledges) <= 0:
            raise LogicException('未关联知识点')

        mc_ids = list(Question.objects.filter(knowledge__id__in=knowledges, question_type='MC').values_list('id', flat=True))
        if len(mc_ids) < int(self.request.data['MC']['total']):
            raise LogicException('单选题库数量不足')

        ma_ids = list(Question.objects.filter(knowledge__id__in=knowledges, question_type='MA').values_list('id', flat=True))
        if len(ma_ids) < int(self.request.data['MA']['total']):
            raise LogicException('多选题库数量不足')

        tf_ids = list(Question.objects.filter(knowledge__id__in=knowledges, question_type='TF').values_list('id', flat=True))
        if len(tf_ids) < int(self.request.data['TF']['total']):
            raise LogicException('判断题库数量不足')

        bl_ids = list(Question.objects.filter(knowledge__id__in=knowledges, question_type='BL').values_list('id', flat=True))
        if len(bl_ids) < int(self.request.data['BL']['total']):
            raise LogicException('填空题库数量不足')

        sa_ids = list(Question.objects.filter(knowledge__id__in=knowledges, question_type='SA').values_list('id', flat=True))
        if len(sa_ids) < int(self.request.data['SA']['total']):
            raise LogicException('简答题库数量不足')

        start_time = GetPostParaOrNone(self.request.data, 'start_time')
        if start_time in ['', None]:
            # 不定时
            with transaction.atomic():
                exam_new = self.store_exam(self.request, serializer) 
        else:
            with transaction.atomic():
                exam_new = self.store_exam(self.request, serializer)
                # 获取单选题
                rand_ids = random.sample(mc_ids, int(self.request.data['MC']['total']))
                mc_questions = Question.objects.filter(id__in=rand_ids)

                # 获取多选题
                rand_ids = random.sample(ma_ids, int(self.request.data['MA']['total']))
                ma_questions = Question.objects.filter(id__in=rand_ids)
                
                # 获取判断题
                rand_ids = random.sample(tf_ids, int(self.request.data['TF']['total']))
                tf_questions = Question.objects.filter(id__in=rand_ids)

                # 获取填空题
                rand_ids = random.sample(bl_ids, int(self.request.data['BL']['total']))
                bl_questions = Question.objects.filter(id__in=rand_ids)

                # 获取简答题
                rand_ids = random.sample(sa_ids, int(self.request.data['SA']['total']))
                sa_questions = Question.objects.filter(id__in=rand_ids)
                
                mc_single_score = int(self.request.data['MC']['score']) / int(self.request.data['MC']['total'])
                ma_single_score = int(self.request.data['MA']['score']) / int(self.request.data['MA']['total'])
                tf_single_score = int(self.request.data['TF']['score']) / int(self.request.data['TF']['total'])
                bl_single_score = int(self.request.data['BL']['score']) / int(self.request.data['BL']['total'])
                sa_single_score = int(self.request.data['SA']['score']) / int(self.request.data['SA']['total'])
                order = 0
                for mcq in mc_questions:
                    order = order + 1
                    eq = ExamQuestion.addOne(exam_new, order, mcq, mc_single_score)
                for maq in ma_questions:
                    order = order + 1
                    eq = ExamQuestion.addOne(exam_new, order, maq, ma_single_score)
                for tfq in tf_questions:
                    order = order + 1
                    eq = ExamQuestion.addOne(exam_new, order, tfq, tf_single_score)
                for blq in bl_questions:
                    order = order + 1
                    eq = ExamQuestion.addOne(exam_new, order, blq, bl_single_score)
                for saq in sa_questions:
                    order = order + 1
                    eq = ExamQuestion.addOne(exam_new, order, saq, sa_single_score)
        
        serializer = ExamCreateSerializer(exam_new)
        self.response_format["data"] = serializer.data
    def create(self, request, *args, **kwargs):
        try:
            super(ExamCreateViewSet, self).create(request, *args, **kwargs)
            self.response_format["message"] = "试卷创建成功"
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class PaperListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):

    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Paper.objects.all()
    serializer_class = PaperListSerializer 
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]

    def get_queryset(self):
        queryset = Paper.objects.filter(exam__course__teacher = self.request.user.teacher).order_by('-id')
        exam_name = self.request.query_params.get('exam_name', None)
        course_name = self.request.query_params.get('course_name', None)
        course_id = self.request.query_params.get('course_id', None)
        paper_status = self.request.query_params.get('paper_status', None)
        studentid = self.request.query_params.get('studentid', None)
        username = self.request.query_params.get('username', None)
        banned = [None,'']
        if exam_name not in banned:
            queryset = queryset.filter(exam__exam_name__icontains=exam_name)
        if course_name not in banned:
            queryset = queryset.filter(exam__course__course_name__icontains=course_name)
        if course_id not in banned:
            queryset = queryset.filter(exam__course=course_id)
        if paper_status not in banned:
            queryset = queryset.filter(score__isnull=True) if str(paper_status) == "0" else queryset.filter(score__isnull=False)
        if studentid not in banned:
            queryset = queryset.filter(student__studentID=studentid)
        if username not in banned:
            queryset = queryset.filter(student__user__real_name__icontains=username)
        return queryset

class ExamOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = ExamSerializer 
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ExamOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Exam.objects.filter(Q(id = self.kwargs['pk']), Q(owner=self.request.user))

    def retrieve(self, request, exam_id=None):
        queryset = Exam.objects.filter(Q(owner=self.request.user))
        try:
            one = queryset.get(id = self.kwargs['exam_id'])
            serializer = ExamSerializer(one, context={"request": request})
            self.response_format["data"] = serializer.data
        except Exam.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '考试ID不存在'
        
        return Response(self.response_format)

class ExamQuestionRemoveView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ExamQuestionRemoveView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            return Student.objects.get(user__id = obj_id)
        except Student.DoesNotExist:
            return None

    def post(self, request, *args, **kwargs):
        try:
            examquestion_id = request.data['examquestion_id']
            examquestion = ExamQuestion.objects.get(id=examquestion_id, exam__owner=self.request.user)
            if timeutil.comp(datetime.now(), examquestion.exam.start_time) > 0:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.response_format["message"] = "考试已开始，无法进行编辑！"
                return Response(self.response_format)
            assert examquestion.question is not None
            examquestion.question = None
            examquestion.save()
            self.response_format["message"] = '试题删除成功'
            return Response(self.response_format)
        except Exception as e:
            print(str(e))
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "参数错误"
            return Response(self.response_format)

class ExamQuestionAddView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ExamQuestionAddView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            return Student.objects.get(user__id = obj_id)
        except Student.DoesNotExist:
            return None

    def post(self, request, *args, **kwargs):
        try:
            examquestion_id = request.data['examquestion_id']
            question_id = request.data['question_id']
            examquestion = ExamQuestion.objects.get(id=examquestion_id, exam__owner=self.request.user)
            if timeutil.comp(datetime.now(), examquestion.exam.start_time) > 0:
                self.response_format["error_code"] = ErrorCode.comon_error.value
                self.response_format["message"] = "考试已开始，无法进行编辑！"
                return Response(self.response_format)
            question = Question.objects.get(id=question_id)
            assert examquestion.question is None
            assert question.question_type == examquestion.question_type
            examquestion.question = question
            examquestion.save()
            self.response_format["message"] = '试题添加成功'
            return Response(self.response_format)
        except Exception as e: 
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '参数错误'
            return Response(self.response_format)


